/******************************************************************************/
package jamie.org.sil.www.UsxConfigEditor;

import java.awt.Component;
import javax.swing.*;
import javax.swing.table.*;


/******************************************************************************/
/**
 * 
 * <p>Descriptor of a single tag in a config file.
 *
 * There must be one of these for every tag for which we require input from the
 * user.  Each contains various information (XML tag name, on-screen prompt,
 * tool-tip, etc).  There are various flavours reflecting the kind of input
 * we are prepared to take (for example, plain text, selections from lists,
 * etc).
 * <p>
 *
 * Each also records the number of the tab on the tabbed panel of the GUI on
 * which it appears.  This of course implies that the caller needs to provide
 * this information at the time the tags are described.  At the same time,
 * to do this on every single tag would mean that the information was
 * repeated in many places, which would make it difficult to move tags between
 * tabs on the GUI.  I therefore recommend that you add all the tags
 * for a given tab contiguously, and that you use the static <i>setTabNo</i>
 * method before you do this, which sets the tab number for all subsequent
 * tags.
 * <p>
 *
 * Note that the order in which tags are added to the collection matters --
 * we write stuff out in this order, so if it is important that tags come out
 * together on the output (for example if, as with Dublin Core, a group of
 * tags all have to sit together in some higher level structure), they must
 * be added to the collection contiguously.
 * <p>
 *
 * On the subject of higher level structures, you can add details of a prefix
 * or a suffix to the tags.  When writing out a given tag, if it has an
 * associated prefix, that text is written out first; and if it has an
 * associated suffix, that text is written out afterwards.  This provides a
 * simple means of producing the kind of structuring just discussed.
 * <p>
 */

public class ConfigTag
{
  /****************************************************************************/
  /****************************************************************************/
  /**                                                                        **/
  /**                               Public                                   **/
  /**                                                                        **/
  /****************************************************************************/
  /****************************************************************************/

  /****************************************************************************/
  public enum Optionality { C_Optional, C_Mandatory }


  /****************************************************************************/
  public static void setTabNo (int tabNo) { m_StaticTabNo = tabNo; }
  private static int m_StaticTabNo = -1;


  /****************************************************************************/
  /** A generic base class. */

  static public class Generic
  {
    public Object getCanonicalValue () { return ((String) m_Value).trim(); }
    public Object getDefault () { return m_Default; }
    public String getPrefix () { return m_Prefix; }
    public String getSuffix () { return m_Suffix; }
    public String getTooltip () { return m_Tooltip; }
    public String getListOptions () { return m_ListOptions; }
    public String getPrompt () { return m_Prompt; }
    public TableCellRenderer getRenderer (int col) { return (0 == col) ? GuiSupport.instance(mTabNo).makePromptRenderer(m_Optionality) : m_Renderer; }
    public int getTabNo () { return mTabNo; }
    public String getTagName () { return m_TagName; }
    public Object getValue () { return m_Value; }
    public Optionality getOptionality () { return m_Optionality; }
    public boolean isDirty () { return m_Dirty; }
    public boolean isEditable (int col) { return 1 == col; }
    public boolean isHeader () { return null == m_Editor; }
    public boolean isHidden () { return false; }
    public boolean isMissing () { return m_Optionality == Optionality.C_Mandatory && 0 == ((String) getCanonicalValue()).length(); }
    public void setDirty (boolean v) { m_Dirty = false; }
    public Generic setPrefix (String v) { m_Prefix = v; return this; }
    public void setSuffix (String v) { m_Suffix = v; }
    public void setValue (Object v)
    {
      if (!m_Value.equals(v)) m_Dirty = true;
      m_Value = v;
    }


    /**************************************************************************/
    /** Default constructor. */
    
    public Generic () { mTabNo = m_StaticTabNo; }


    /**************************************************************************/
    /** Common constructor.

        @param tagName
        @param prompt
        @param tooltip (taken to be the same as the prompt if supplied as an empty string)
        @param dflt Default value
        @param optionality indicates whether parameter is optional or mandatory
    */
    
    public Generic (String tagName, String prompt, String tooltip, Object dflt, Optionality optionality)
    {
       m_Default = dflt;
       m_Tooltip = (0 == tooltip.length()) ? prompt : tooltip;
       m_Prompt = prompt;
       m_TagName = tagName;
       m_Optionality = optionality;
       m_Value = m_Default;
       mTabNo = m_StaticTabNo;
    }


    /**************************************************************************/
    /** Get the editor for this cell.  In the case of JTextField-based editors,
     *  set the font size first.
     *
     * @param col Column of interest.
     * @return Editor.
     */

    public TableCellEditor getEditor (int col)
    {
      try
      {
        Component c = ((DefaultCellEditor) m_Editor).getComponent();
        c.setFont(c.getFont().deriveFont(GuiSupport.getTableFontSize()));
      }
      catch (Exception e)
      {
      }
      return m_Editor;
    }


    /**************************************************************************/
    /** Populates the tag with details obtained from a config file.

        @param desc Descriptor for config file.
    */
    
    public void populate (XmlFile desc)
    {
      setValue(desc.getValue(getTagName(), getDefault()));
    }

    protected Object m_Default = "";
    protected Object m_Value = "";
    protected Optionality m_Optionality;
    protected int mTabNo = -1;
    protected String m_ListOptions = "";
    protected String m_Prefix = null;
    protected String m_Prompt = "";
    protected int m_Row = -1;
    protected String m_Suffix = null;
    protected String m_TagName = "";
    protected String m_Tooltip = "";
    protected TableCellEditor m_Editor = null;
    protected TableCellRenderer m_Renderer = null;
    protected boolean m_Dirty = false;
  }


  /****************************************************************************/
  /** Used where boolean values are required from the user. */

  static public class Boolean extends Generic
  {
    @Override public boolean isMissing () { return false; }
    @Override public Object getCanonicalValue () { return m_Value; }
    public Boolean (String tagName, String prompt, String tooltip, boolean dflt, Optionality optionality)
    {
      super(tagName, prompt, tooltip, dflt, optionality);
      m_Renderer = GuiSupport.instance(mTabNo).makeBooleanRenderer(optionality);
      m_Editor = GuiSupport.makeCheckBoxBasedEditor();
    }
  }


  /****************************************************************************/
  /** Used where file paths are required from the user. */

  static public class File extends Generic
  {
    public File (String tagName, String prompt, String tooltip, String dflt, Optionality optionality)
    {
      super(tagName, prompt, tooltip, dflt, optionality);
      m_Renderer = GuiSupport.instance(mTabNo).makeTextRenderer(optionality);
      m_Editor = GuiSupport.instance(mTabNo).makeFileEditor(prompt);
   }
  }


  /****************************************************************************/
  /** A dummy tag whose only effect is to generate a header on the screen. */

  static public class Header extends Generic
  {
    @Override public TableCellRenderer getRenderer (int col) { return m_Renderer; }
    @Override public boolean isEditable (int col) { return false; }
    public Header (String text)
    {
      m_Prompt = text;
      m_Renderer = GuiSupport.instance(mTabNo).makeHeaderRenderer();
      m_Editor = null;
    }
  }


  /****************************************************************************/
  static public class List extends Generic
  {
    public List (String tagName, String prompt, String tooltip, String dflt, Optionality optionality, String options)
    {
      super(tagName, prompt, tooltip, dflt, optionality);
      m_ListOptions = options;
      m_Renderer = GuiSupport.instance(mTabNo).makeTextRenderer(optionality);
      m_Editor = GuiSupport.makeComboBasedEditor(m_ListOptions);
    }
  }


  /****************************************************************************/
  /** Used where the input from the user has to come from a defined list of
   *  options.
   */
  static public class Text extends Generic
  {
    public Text (String tagName, String prompt, String tooltip, String dflt, Optionality optionality)
    {
      super(tagName, prompt, tooltip, dflt, optionality);
      m_Renderer = GuiSupport.instance(mTabNo).makeTextRenderer(optionality);
      m_Editor = GuiSupport.makeTextFieldBasedEditor();
   }
  }
}
